19. Context Isolation и обмен данными между процессами в Electron

Что такое contextIsolation?

Context Isolation (изоляция контекста) — это функция безопасности в Electron, которая изолирует код предзагрузки (preload) и код рендерера (renderer) от глобального контекста. Это предотвращает возможность внедрения вредоносного кода через уязвимости в веб-приложении.

Когда contextIsolation включена (по умолчанию в Electron 12 и выше), код рендерера и код предзагрузки выполняются в разных контекстах, что делает невозможным прямой доступ к Node.js API из рендерера. Вместо этого для взаимодействия между процессами используется Inter-Process Communication (IPC).


Настройка contextIsolation

Шаг 1: Включение contextIsolation

По умолчанию contextIsolation включена в Electron 12 и выше. Однако, если вы используете более старую версию или хотите явно включить/выключить эту функцию, вы можете настроить её в webPreferences при создании окна.

Пример настройки contextIsolation в index.js:

const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
    const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'), // Файл предзагрузки
            contextIsolation: true, // Включение изоляции контекста
            nodeIntegration: false, // Отключение интеграции Node.js в рендерере
        },
    });

    mainWindow.loadFile('index.html');
}

app.whenReady().then(() => {
    createWindow();
});

Шаг 2: Создание файла предзагрузки (preload.js)

Файл предзагрузки (preload.js) используется для настройки безопасного взаимодействия между основным процессом и рендерером. В этом файле вы можете предоставить рендереру доступ к определённым API или функциям, используя Inter-Process Communication (IPC).

Пример содержимого preload.js:

const { contextBridge, ipcRenderer } = require('electron');

// Предоставляем рендереру безопасный доступ к IPC
contextBridge.exposeInMainWorld('YourApp', {
    sendMessage: (message) => ipcRenderer.invoke('message-to-main', message),
    onMessage: (callback) => ipcRenderer.invoke('message-to-renderer', callback),
});

Обмен данными между основным процессом и рендерером

Шаг 1: Отправка данных из рендерера в основной процесс

Для отправки данных из рендерера в основной процесс используется метод ipcRenderer.send. В файле предзагрузки мы предоставили рендереру доступ к этому методу через contextBridge.

Пример отправки данных из рендерера:

// В рендерере (renderer.js)
window.YourApp.sendMessage('Привет из рендерера!');

Обработка данных в основном процессе:

// В основном процессе (index.js)
const { ipcMain } = require('electron');

ipcMain.handle('message-to-main', (event, message) => {
    console.log('Получено сообщение из рендерера:', message);
    return "Получено";
});

Шаг 2: Отправка данных из основного процесса в рендерер

Для отправки данных из основного процесса в рендерер используется метод ipcRenderer.on, который мы также предоставили рендереру через contextBridge.

Пример отправки данных из основного процесса:

// В основном процессе (index.js)
const { BrowserWindow } = require('electron');

const mainWindow = BrowserWindow.getFocusedWindow();
mainWindow.webContents.send('message-to-renderer', 'Привет из основного процесса!');

Обработка данных в рендерере:

// В рендерере (renderer.js)
window.electronAPI.onMessage((event, message) => {
    console.log('Получено сообщение из основного процесса:', message);
});

Практическое задание

  1. Создайте простое Electron-приложение:

    • Создайте окно с включённой contextIsolation и отключённой nodeIntegration.
    • Добавьте файл предзагрузки (preload.js), который предоставляет рендереру доступ к IPC.
  2. Реализуйте обмен данными:

    • Добавьте кнопку в интерфейсе приложения, которая отправляет сообщение в основной процесс.
    • В основном процессе выведите полученное сообщение в консоль.
    • Отправьте ответ из основного процесса в рендерер и отобразите его в интерфейсе.
  3. Добавьте обработку ошибок:

    • Убедитесь, что приложение корректно обрабатывает случаи, когда сообщения не доходят или содержат неверные данные.

Дополнительные задания:

  • Реализуйте двусторонний обмен данными между процессами, например, отправку данных из рендерера, их обработку в основном процессе и возврат результата в рендерер.
  • Добавьте возможность отправки файлов из рендерера в основной процесс и их обработки.

Заключение

contextIsolation — это важная функция безопасности в Electron, которая предотвращает уязвимости, связанные с доступом к Node.js API из рендерера. Использование contextBridge и IPC позволяет безопасно обмениваться данными между основным процессом и рендерером. В этом занятии мы рассмотрели, как настроить contextIsolation и реализовать обмен данными между процессами.